﻿using Device;
using DryIoc.Messages;
using ImTools;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Prism.Events;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.IO.Packaging;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Interop;
using System.Windows.Markup;
using WebAPI;
using WpfApp.Models;
using static DryIoc.ServiceInfo;

namespace WpfApp.Common
{
    public abstract class UdpService : BackgroundService
    {
        protected bool runflag = false;
        protected int port { get; set; }
        protected string ip { get; set; }
        protected int remote_port { get; set; }
        protected string remote_ip { get; set; }
        protected bool IsClientInitOK = false;
        protected UdpClient client = null;
        private bool InitUdpClient()
        {
            IsClientInitOK = false;
            try
            {
                client = new UdpClient(new IPEndPoint(IPAddress.Parse(ip), port)) { EnableBroadcast = true };
                IsClientInitOK = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return IsClientInitOK;
            }
            return IsClientInitOK;
        }
        protected bool StartUdpClient()
        {
            if (!runflag)
                runflag = true;
            if (!IsClientInitOK)
            {
                InitUdpClient();
            }
            return runflag;
        }
        protected bool StopUdpClient()
        {
            if (IsClientInitOK)
            {
                if (client != null)
                {
                    client.Close();
                    client?.Dispose();
                    client = null;
                }
                IsClientInitOK = false;
            }
            if (runflag)
                runflag = false;
            return true;
        }
    }
    public enum MsgType
    {
        Log,
        AnchorInfo
    }
    public struct MsgEventArgs
    {
        public MsgEventArgs(string m, MsgType msgType = MsgType.Log)
        {
            MsgType = msgType;
            msg = m;
        }
        public MsgType MsgType;
        public string msg;
    }
    public delegate void MsgEventHandler(MsgEventArgs e);
    public interface IUdpService
    {
        event MsgEventHandler RecvMsgEvent;
        void SettingIpPort(string Ip, int port = 8070);
        bool Sart();
        bool Stop();
        void ConfigDistance(Anchor selectedAnchor);
        Task Refresh();
        void AddTagId(Anchor selectedAnchor, string v);
        void ClearTagId(Anchor selectedAnchor);
    }

    public class AnchorUdpService : UdpService, IUdpService
    {
        public event MsgEventHandler RecvMsgEvent = null;
        private ConcurrentDictionary<string, Anchor> anchorDic = new ConcurrentDictionary<string, Anchor>();
        private CancellationTokenSource source = new CancellationTokenSource();
        private readonly CancellationToken _cancellationToken;
        public AnchorUdpService()
        {
            _cancellationToken = source.Token;
        }
        public void SettingIpPort(string _ip, int _port = 8070)
        {
            ip = _ip;
            port = _port;
        }
        private void SetGlobalbServerId(string id)
        {
            id = ip;
            Global.bServerId = StringHexByteUtils.StringIpToBytes(id);
        }
        public async Task Refresh()
        {
            IsRecvHandShake = false;
            //建立连接
            SendHandShake();
            //确认建立连接
            while (!IsRecvHandShake)
            {
                await Task.Delay(1);
            }
            if (anchorDic.Count > 0)
            {
                foreach (var item in anchorDic)
                {
                    IsRecvReadInfo = false;
                    ReadAnchorInfo(item.Value);
                    while (!IsRecvReadInfo)
                    {
                        await Task.Delay(1);
                    }

                    IsRecvReadInfo = false;
                    ReadDistance(item.Value);
                    while (!IsRecvReadInfo)
                    {
                        await Task.Delay(1);
                    }

                    IsRecvReadInfo = false;
                    ReadTagIds(item.Value);
                    while (!IsRecvReadInfo)
                    {
                        await Task.Delay(1);
                    }

                    var options = new JsonSerializerOptions { WriteIndented = true };
                    string jsonString = JsonSerializer.Serialize(item.Value, options);
                    RecvMsgEvent?.Invoke(new MsgEventArgs($"{jsonString}", MsgType.Log));
                    RecvMsgEvent?.Invoke(new MsgEventArgs($"{jsonString}", MsgType.AnchorInfo));
                }
            }
        }


        bool IsRecvHandShake = false;
        bool IsRecvReadInfo = false;
        /// <summary>
        /// 发送广播握手消息
        /// </summary>
        private void SendHandShake()
        {
            SetGlobalbServerId(null);
            var bMsg = ServerProtocolEncode.GenHandShake(Global.bServerId, null);
            var sMsg = StringHexByteUtils.ByteToHexString(bMsg);
            string broadCast = string.Join(".", ip.Split('.').Take(3)) + ".255";
            client.Send(bMsg, bMsg.Length, new IPEndPoint(IPAddress.Parse(broadCast), 8070));
            string m = StringHexByteUtils.ByteToHexString(bMsg.ToArray());
            RecvMsgEvent?.Invoke(new MsgEventArgs($"Send:{m}"));
        }
        /// <summary>
        /// 接收握手消息反馈
        /// </summary>
        /// <param name="remote_ip"></param>
        /// <param name="data"></param>
        private void RecvHandShake(string remote_ip, byte[] data)
        {
            var anchorid = StringHexByteUtils.ByteToHexString(data).Replace(" ", "");
            if (!string.IsNullOrEmpty(anchorid) && !anchorDic.ContainsKey(anchorid))
            {
                Anchor anchor = new Anchor() { ID = data, AnchorId = anchorid, Ip = remote_ip };
                var result = anchorDic.AddOrUpdate(anchorid, anchor, (anchorid, a) =>
                 {
                     if (a.Ip != remote_ip)
                     {
                         a.Ip = remote_ip;
                         return a;
                     }
                     return null;
                 });
            }
            IsRecvHandShake = true;
        }
        /// <summary>
        /// 发送心跳
        /// </summary>
        private void SendHeartBeat()
        {

        }
        /// <summary>
        /// 接收心跳
        /// </summary>
        /// <param name="remote_ip"></param>
        /// <param name="data"></param>
        private void RecvHeartBeat(string remote_ip, byte[] data)
        {
            //var anchorid = StringHexByteUtils.ByteToHexString(data).Replace(" ", "");
            //if (anchorid != null && !anchorDic.ContainsKey(anchorid))
            //{
            //    var result = anchorDic.AddOrUpdate(anchorid, remote_ip, (k, v) =>
            //    {
            //        if (v != remote_ip)
            //        {
            //            v = remote_ip;
            //            return k;
            //        }
            //        return null;
            //    });
            //}
            //IsRecvHandShake = true;
        }





        private void ReadAnchorInfo(Anchor anchor)
        {
            var data = new byte[]
            {
                0x04,//Bootloader 版本号
                0x00,
                0x06,//程序版本号
                0x00,
                0x07,//编译 PC，ASCII 码
                0x00,
                0x08,//编译日期，ASCII 码
                0x00,
                0x09,//编译时间，ASCII 码
                0x00,
                0x26,//UWB Channel
                0x00,
                0x27,//UWB Mode：每个通道下分模式
                0x00,
                0x28,//Server IP
                0x00,
                0xE0,//硬件类型
                0x00,
                0xE1,//SN 号(ASCII 码)
                0x00,
                0xE2,//ID 号
                0x00,
                0xE3,//MAC
                0x00
            };
            var body = ServerProtocolEncode.GenReadAnchor(anchor.ID, Global.bServerId, data);
            SendReadAnchorInfo(anchor.Ip, body);
        }
        /// <summary>
        /// 读取基站信息
        /// </summary>
        /// <param name="AnchorId"></param>
        /// <param name="ip"></param>
        private void SendReadAnchorInfo(string AnchorIp, byte[] body)
        {
            client.Send(body, body.Length, new IPEndPoint(IPAddress.Parse(AnchorIp), 8070));
            RecvMsgEvent?.Invoke(new MsgEventArgs($"Send:{BitConverter.ToString(body)}"));
        }


        private void ReadDistance(Anchor anchor)
        {
            var data = new byte[]
            {
                0x50,//预警距离 单位：厘米
                0x00,
                0x51,//报警距离 单位：厘米 
                0x00,
                0x52,//免报距离 单位：厘米
                0x00
             };
            var body = ServerProtocolEncode.GenReadAnchor(anchor.ID, Global.bServerId, data);
            SendReadAnchorInfo(anchor.Ip, body);
        }

        private byte currentpackageId = 0x00;
        private byte totalpackageId = 0x00;
        private List<string> Tagids = new List<string>();
        /// <summary>
        /// 读取白名单
        /// </summary>
        /// <param name="anchor"></param>
        /// <param name="packageId"></param>
        private void ReadTagIds(Anchor anchor, byte packageId = 0x00)
        {
            if (packageId == 0x00)
            {
                Tagids = new List<string>();
            }
            var data = new byte[]
            {
                0x30,//白名单
                0x01,
                packageId
            };
            var body = ServerProtocolEncode.GenReadAnchor(anchor.ID, Global.bServerId, data);
            SendReadAnchorInfo(anchor.Ip, body);
        }
        /// <summary>
        /// 清空白名单
        /// </summary>
        /// <param name="anchor"></param>
        private void ClearTagIds(Anchor anchor)
        {
            var data = new byte[]
            {
                0x30,
                0x01,
                0xff
            };
            var body = ServerProtocolEncode.GenSetAnchorParams(anchor.ID, Global.bServerId, data);
            SendReadAnchorInfo(anchor.Ip, body);
        }




        private void RecvReadAnchorInfo(string remote_ip, byte[] id, byte[] data)
        {
            if (id == null || id.Length < 3)
            {
                IsRecvReadInfo = true;
                return;
            }
            if (data == null)
            {
                IsRecvReadInfo = true;
                return;
            }
            if (string.IsNullOrEmpty(remote_ip))
            {
                IsRecvReadInfo = true;
                return;
            }
            var tlvs = ServerProtocolDecode.GetTlvList_New(data);
            var anchorid = StringHexByteUtils.ByteToHexString(id).Replace(" ", "");
            if (string.IsNullOrEmpty(anchorid))
            {
                IsRecvReadInfo = true;
                return;
            }
            if (anchorDic.TryGetValue(anchorid, out Anchor anchor))
            {
                anchor.Ip = remote_ip;
                foreach (var tlv in tlvs)
                {
                    RecvMsgEvent?.Invoke(new MsgEventArgs($"T:0x{tlv.type.ToString("X")}---L:{tlv.length}---V:{StringHexByteUtils.ByteToHexString(tlv.value)}"));
                    if (tlv.type == 0x04 && tlv.length == 3)
                    {
                        string bl = string.Join(".", tlv.value);
                        anchor.Bootloader = $"{bl}";
                    }
                    if (tlv.type == 0x06 && tlv.length == 3)
                    {
                        string fwv = string.Join(".", tlv.value);
                        anchor.FwVersion = $"{fwv}";
                    }
                    if (tlv.type == 0x07 && tlv.length > 0 && tlv.length < 17)
                    {
                        anchor.BulidPc = $"{Encoding.ASCII.GetString(tlv.value)}";
                    }
                    if (tlv.type == 0x08 && tlv.length > 0 && tlv.length < 17)
                    {
                        string date = Encoding.ASCII.GetString(tlv.value);
                        var d = DateTime.Parse(date);
                        anchor.BulidDate = $"{d.ToString("yyyy/MM/dd")}";
                    }
                    if (tlv.type == 0x09 && tlv.length > 0 && tlv.length < 17)
                    {
                        anchor.BulidTime = $"{Encoding.ASCII.GetString(tlv.value)}";
                    }
                    if (tlv.type == 0x26 && tlv.length == 1)
                    {
                        anchor.Channel = (int)tlv.value[0];//2,5
                    }
                    if (tlv.type == 0x27 && tlv.length == 1)
                    {
                        anchor.Mode = (int)tlv.value[0];//1,2,3,4
                    }
                    if (tlv.type == 0x28 && tlv.length == 4)
                    {
                        string serverIp = string.Join(".", tlv.value);
                        anchor.ServerIp = serverIp;
                    }
                    if (tlv.type == 0x30 && tlv.length == 1)
                    {
                        currentpackageId = tlv.value[0];
                    }
                    if (tlv.type == 0x31 && tlv.length == 1)
                    {
                        totalpackageId = tlv.value[0];
                    }
                    if ((tlv.type >= 0x32 && tlv.type <= 0x4f) && tlv.length == 4)
                    {
                        string tagId = StringHexByteUtils.ByteToHexString(tlv.value).Replace(" ", "");
                        if (!string.IsNullOrEmpty(tagId) && !Tagids.Contains(tagId))
                        {
                            Tagids.Add(tagId);
                        }
                        anchor.TagIds = new List<string>(Tagids);
                    }
                    if (tlv.type == 0x50 && tlv.length == 2)
                    {
                        anchor.WarningDistance = BitConverter.ToUInt16(tlv.value, 0);
                    }
                    if (tlv.type == 0x51 && tlv.length == 2)
                    {
                        anchor.AlarmDistance = BitConverter.ToUInt16(tlv.value, 0);
                    }
                    if (tlv.type == 0x52 && tlv.length == 2)
                    {
                        anchor.UnAlarmDistance = BitConverter.ToUInt16(tlv.value, 0);
                    }
                    if (tlv.type == 0xE0 && tlv.length == 3)
                    {
                        anchor.FwType = StringHexByteUtils.ByteToHexString(tlv.value);
                    }
                    if (tlv.type == 0xE1 && tlv.length > 0 && tlv.length < 21)
                    {
                        string sn = $"{Encoding.ASCII.GetString(tlv.value)}";
                        anchor.SN = sn;
                    }
                    if (tlv.type == 0xE2 && tlv.length == 4)
                    {
                        List<string> l = new List<string>();
                        tlv.value.ForEach(e => l.Add(e.ToString("X2")));
                        anchor.AnchorId = string.Join("", l);
                    }
                    if (tlv.type == 0xE3 && tlv.length == 6)
                    {
                        List<string> l = new List<string>();
                        tlv.value.ForEach(e => l.Add(e.ToString("x2")));
                        string MAC = string.Join(":", l);
                        anchor.MAC = MAC;
                    }
                }
            }
            IsRecvReadInfo = true;
        }
        private void SendSettingAnchor()
        {


        }
        private void RecvSettingAnchor(string remote_ip, byte[] data)
        {
            if (data == null)
                return;
            string m = StringHexByteUtils.ByteToHexString(data?.ToArray());
            RecvMsgEvent?.Invoke(new MsgEventArgs($"Recv:{m}"));
            var tlvs = ServerProtocolDecode.GetTlvList_New(data);
            foreach (var tlv in tlvs)
            {
                RecvMsgEvent?.Invoke(new MsgEventArgs($"T:0x{tlv.type.ToString("X")}---L:{tlv.length}---V:{StringHexByteUtils.ByteToHexString(tlv.value)}"));
            }

        }
        private void SendUpdateAnchor()
        {


        }
        private void RecvUpdateAnchor(string remote_ip, byte[] data)
        {


        }
        public bool Sart()
        {
            StartUdpClient();
            base.StartAsync(_cancellationToken);
            return true;
        }
        public bool Stop()
        {
            StopUdpClient();
            base.StopAsync(_cancellationToken);
            return true;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                Receive();
                await Task.Delay(1, stoppingToken);
            }
        }
        private void Receive()
        {
            if (!runflag)
                return;
            if (client == null)
                return;
            if (client.Client == null)
                return;
            if (client.Available <= 0)
                return;
            if (client.Client.Available <= 0)
                return;
            try
            {
                IPEndPoint remoteIpep = null;
                byte[] buffer = client.Receive(ref remoteIpep);
                if (remoteIpep != null)
                {
                    remote_ip = remoteIpep.Address?.ToString();
                    remote_port = remoteIpep.Port;
                }
                if (buffer == null || buffer.Length < 0)
                    return;
                var workTask = Task.Run(() =>
                {
                    byte[] buf = new byte[buffer.Length];
                    Array.Copy(buffer, 0, buf, 0, buffer.Length);
                    BufferConverters(remote_ip, buf);
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return;
            }
            if (!runflag)
                return;
        }
        private void BufferConverters(string remote_ip, byte[] buffers)
        {
            if (remote_ip == ip)
            {
                return;
            }
            if (buffers.Length > 13)
            {
                string m = StringHexByteUtils.ByteToHexString(buffers);
                RecvMsgEvent?.Invoke(new MsgEventArgs($"Recv:{m}"));
                byte[] payload = null;
                byte header = buffers[0];
                if (header != 0xfc)
                    return;
                byte msgtype = buffers[1];
                byte[] remoteID = buffers[2..6];
                byte[] localID = buffers[6..10];
                byte[] length = buffers[10..12];
                int l = BitConverter.ToInt16(length, 0);
                if (l > 0)
                    payload = buffers.Skip(12).Take(l).ToArray();//[12..l];
                byte[] crcs = buffers[^2..];
                switch (msgtype)
                {
                    case 0x02:
                        RecvHandShake(remote_ip, localID);
                        break;
                    case 0x04:
                        RecvHeartBeat(remote_ip, localID);
                        break;
                    case 0x06:
                        RecvUpdateAnchor(remote_ip, localID);
                        break;
                    case 0x12:
                        RecvReadAnchorInfo(remote_ip, localID, payload);
                        break;
                    case 0x14:
                        RecvSettingAnchor(remote_ip, payload);
                        break;
                    default:
                        break;
                }
            }
        }

        public async void ConfigDistance(Anchor selectedAnchor)
        {
            IsRecvHandShake = false;
            //建立连接
            SendHandShake();
            //确认建立连接
            while (!IsRecvHandShake)
            {
                await Task.Delay(1);
            }

            byte[] w = StringHexByteUtils.Uint16ToBytes(selectedAnchor.WarningDistance).Reverse().ToArray();
            byte[] a = StringHexByteUtils.Uint16ToBytes(selectedAnchor.AlarmDistance).Reverse().ToArray();
            byte[] u = StringHexByteUtils.Uint16ToBytes(selectedAnchor.UnAlarmDistance).Reverse().ToArray();
            var tlvList = new List<Tlv>
            {

               new Tlv{ type = 0x50,length=0x02,value=w},
               new Tlv{ type = 0x51,length=0x02,value=a},
               new Tlv{type=0x52,length=0x02,value = u }
            };
            var payload = ServerProtocolEncode.PacketTlvList(tlvList);

            var data = ServerProtocolEncode.GenSetAnchorParams(selectedAnchor.ID, Global.bServerId, payload);
            client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse(selectedAnchor.Ip), 8070));
            RecvMsgEvent?.Invoke(new MsgEventArgs($"Send:{BitConverter.ToString(data)}"));
        }

        public async void AddTagId(Anchor selectedAnchor, string v)
        {
            IsRecvHandShake = false;
            //建立连接
            SendHandShake();
            //确认建立连接
            while (!IsRecvHandShake)
            {
                await Task.Delay(1);
            }
            AddTagIds(selectedAnchor);
        }
        private void AddTagIds(Anchor anchor)
        {
            var tlvList = new List<Tlv>
            {
               new Tlv{ type = 0x30,length=0x01,value=new byte[]{ 0x00 } },
               new Tlv{ type = 0x32,length=0x04,value=new byte[]{ 0x40,0x10,0x01,0x01 }},
               new Tlv{type=0x33,length=0x04,value=new byte[]{ 0x3E, 0x00, 0x03, 0x0C } }
            };
            var payload = ServerProtocolEncode.PacketTlvList(tlvList);
            var data = ServerProtocolEncode.GenSetAnchorParams(anchor.ID, Global.bServerId, payload);
            client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse(anchor.Ip), 8070));
        }

        public async void ClearTagId(Anchor selectedAnchor)
        {
            IsRecvHandShake = false;
            //建立连接
            SendHandShake();
            //确认建立连接
            while (!IsRecvHandShake)
            {
                await Task.Delay(1);
            }
            ClearTagIds(selectedAnchor);

            Tagids = new List<string>();
            selectedAnchor.TagIds = new List<string>();
        }
    }
}
